home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / libs / unixlib.lha / unix / src / zoneinfo / zic.c < prev    next >
C/C++ Source or Header  |  1996-12-01  |  43KB  |  1,837 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Arthur David Olson of the National Cancer Institute.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)zic.c    5.3 (Berkeley) 4/20/91";
  39. #endif /* not lint */
  40.  
  41. #ifdef notdef
  42. static char    elsieid[] = "@(#)zic.c    4.12";
  43. #endif
  44.  
  45. #include <sys/types.h>
  46. #include <sys/cdefs.h>
  47. #include <sys/stat.h>
  48. #include <time.h>
  49. #include <tzfile.h>
  50. #include <stdio.h>
  51. #include <ctype.h>
  52. #include <string.h>
  53. #include <stdlib.h>
  54.  
  55. #ifndef TRUE
  56. #define TRUE    1
  57. #define FALSE    0
  58. #endif /* !defined TRUE */
  59.  
  60. #ifndef EXIT_FAILURE
  61. #define EXIT_FAILURE 1
  62. #endif
  63.  
  64. #ifndef EXIT_SUCCESS
  65. #define EXIT_SUCCESS 0
  66. #endif
  67.  
  68. struct rule {
  69.     const char *    r_filename;
  70.     int        r_linenum;
  71.     const char *    r_name;
  72.  
  73.     int        r_loyear;    /* for example, 1986 */
  74.     int        r_hiyear;    /* for example, 1986 */
  75.     const char *    r_yrtype;
  76.  
  77.     int        r_month;    /* 0..11 */
  78.  
  79.     int        r_dycode;    /* see below */
  80.     int        r_dayofmonth;
  81.     int        r_wday;
  82.  
  83.     long        r_tod;        /* time from midnight */
  84.     int        r_todisstd;    /* above is standard time if TRUE */
  85.                     /* or wall clock time if FALSE */
  86.     long        r_stdoff;    /* offset from standard time */
  87.     const char *    r_abbrvar;    /* variable part of abbreviation */
  88.  
  89.     int        r_todo;        /* a rule to do (used in outzone) */
  90.     time_t        r_temp;        /* used in outzone */
  91. };
  92.  
  93. /*
  94. **    r_dycode        r_dayofmonth    r_wday
  95. */
  96.  
  97. #define DC_DOM        0    /* 1..31 */    /* unused */
  98. #define DC_DOWGEQ    1    /* 1..31 */    /* 0..6 (Sun..Sat) */
  99. #define DC_DOWLEQ    2    /* 1..31 */    /* 0..6 (Sun..Sat) */
  100.  
  101. struct zone {
  102.     const char *    z_filename;
  103.     int        z_linenum;
  104.  
  105.     const char *    z_name;
  106.     long        z_gmtoff;
  107.     const char *    z_rule;
  108.     const char *    z_format;
  109.  
  110.     long        z_stdoff;
  111.  
  112.     struct rule *    z_rules;
  113.     int        z_nrules;
  114.  
  115.     struct rule    z_untilrule;
  116.     time_t        z_untiltime;
  117. };
  118.  
  119. extern char *    icatalloc __P((char * old, const char * new));
  120. extern char *    icpyalloc __P((const char * string));
  121. extern void    ifree __P((char * p));
  122. extern char *    imalloc __P((int n));
  123. extern char *    irealloc __P((char * old, int n));
  124. extern int    link __P((const char * fromname, const char * toname));
  125. extern char *    optarg;
  126. extern int    optind;
  127. static void    addtt __P((time_t starttime, int type));
  128. static int    addtype
  129.             __P((long gmtoff, const char * abbr, int isdst,
  130.             int ttisstd));
  131. static void    addleap __P((time_t t, int positive, int rolling));
  132. static void    adjleap __P((void));
  133. static void    associate __P((void));
  134. static int    ciequal __P((const char * ap, const char * bp));
  135. static void    convert __P((long val, char * buf));
  136. static void    dolink __P((const char * fromfile, const char * tofile));
  137. static void    eat __P((const char * name, int num));
  138. static void    eats __P((const char * name, int num,
  139.             const char * rname, int rnum));
  140. static long    eitol __P((int i));
  141. static void    error __P((const char * message));
  142. static char **    getfields __P((char * buf));
  143. static long    gethms __P((char * string, const char * errstrng,
  144.             int signable));
  145. static void    infile __P((const char * filename));
  146. static void    inleap __P((char ** fields, int nfields));
  147. static void    inlink __P((char ** fields, int nfields));
  148. static void    inrule __P((char ** fields, int nfields));
  149. static int    inzcont __P((char ** fields, int nfields));
  150. static int    inzone __P((char ** fields, int nfields));
  151. static int    inzsub __P((char ** fields, int nfields, int iscont));
  152. static int    itsabbr __P((const char * abbr, const char * word));
  153. static int    itsdir __P((const char * name));
  154. static int    lowerit __P((int c));
  155. static char *    memcheck __P((char * tocheck));
  156. static int    mkdirs __P((char * filename));
  157. static void    newabbr __P((const char * abbr));
  158. static long    oadd __P((long t1, long t2));
  159. static void    outzone __P((const struct zone * zp, int ntzones));
  160. static void    puttzcode __P((long code, FILE * fp));
  161. static int    rcomp __P((const void *leftp, const void *rightp));
  162. static time_t    rpytime __P((const struct rule * rp, int wantedy));
  163. static void    rulesub __P((struct rule * rp, char * loyearp, char * hiyearp,
  164.         char * typep, char * monthp, char * dayp, char * timep));
  165. static void    setboundaries __P((void));
  166. static time_t    tadd __P((time_t t1, long t2));
  167. static void    usage __P((void));
  168. static void    writezone __P((const char * name));
  169. static int    yearistype __P((int year, const char * type));
  170.  
  171. static int        charcnt;
  172. static int        errors;
  173. static const char *    filename;
  174. static int        leapcnt;
  175. static int        linenum;
  176. static time_t        max_time;
  177. static int        max_year;
  178. static time_t        min_time;
  179. static int        min_year;
  180. static int        noise;
  181. static const char *    rfilename;
  182. static int        rlinenum;
  183. static const char *    progname;
  184. static int        timecnt;
  185. static int        typecnt;
  186. static int        tt_signed;
  187.  
  188. /*
  189. ** Line codes.
  190. */
  191.  
  192. #define LC_RULE        0
  193. #define LC_ZONE        1
  194. #define LC_LINK        2
  195. #define LC_LEAP        3
  196.  
  197. /*
  198. ** Which fields are which on a Zone line.
  199. */
  200.  
  201. #define ZF_NAME        1
  202. #define ZF_GMTOFF    2
  203. #define ZF_RULE        3
  204. #define ZF_FORMAT    4
  205. #define ZF_TILYEAR    5
  206. #define ZF_TILMONTH    6
  207. #define ZF_TILDAY    7
  208. #define ZF_TILTIME    8
  209. #define ZONE_MINFIELDS    5
  210. #define ZONE_MAXFIELDS    9
  211.  
  212. /*
  213. ** Which fields are which on a Zone continuation line.
  214. */
  215.  
  216. #define ZFC_GMTOFF    0
  217. #define ZFC_RULE    1
  218. #define ZFC_FORMAT    2
  219. #define ZFC_TILYEAR    3
  220. #define ZFC_TILMONTH    4
  221. #define ZFC_TILDAY    5
  222. #define ZFC_TILTIME    6
  223. #define ZONEC_MINFIELDS    3
  224. #define ZONEC_MAXFIELDS    7
  225.  
  226. /*
  227. ** Which files are which on a Rule line.
  228. */
  229.  
  230. #define RF_NAME        1
  231. #define RF_LOYEAR    2
  232. #define RF_HIYEAR    3
  233. #define RF_COMMAND    4
  234. #define RF_MONTH    5
  235. #define RF_DAY        6
  236. #define RF_TOD        7
  237. #define RF_STDOFF    8
  238. #define RF_ABBRVAR    9
  239. #define RULE_FIELDS    10
  240.  
  241. /*
  242. ** Which fields are which on a Link line.
  243. */
  244.  
  245. #define LF_FROM        1
  246. #define LF_TO        2
  247. #define LINK_FIELDS    3
  248.  
  249. /*
  250. ** Which fields are which on a Leap line.
  251. */
  252.  
  253. #define LP_YEAR        1
  254. #define LP_MONTH    2
  255. #define LP_DAY        3
  256. #define LP_TIME        4
  257. #define LP_CORR        5
  258. #define LP_ROLL        6
  259. #define LEAP_FIELDS    7
  260.  
  261. /*
  262. ** Year synonyms.
  263. */
  264.  
  265. #define YR_MINIMUM    0
  266. #define YR_MAXIMUM    1
  267. #define YR_ONLY        2
  268.  
  269. static struct rule *    rules;
  270. static int        nrules;    /* number of rules */
  271.  
  272. static struct zone *    zones;
  273. static int        nzones;    /* number of zones */
  274.  
  275. struct link {
  276.     const char *    l_filename;
  277.     int        l_linenum;
  278.     const char *    l_from;
  279.     const char *    l_to;
  280. };
  281.  
  282. static struct link *    links;
  283. static int        nlinks;
  284.  
  285. struct lookup {
  286.     const char *    l_word;
  287.     const int    l_value;
  288. };
  289.  
  290. static struct lookup const *    byword __P((const char * string,
  291.                     const struct lookup * lp));
  292.  
  293. static struct lookup const    line_codes[] = {
  294.     "Rule",        LC_RULE,
  295.     "Zone",        LC_ZONE,
  296.     "Link",        LC_LINK,
  297.     "Leap",        LC_LEAP,
  298.     NULL,        0
  299. };
  300.  
  301. static struct lookup const    mon_names[] = {
  302.     "January",    TM_JANUARY,
  303.     "February",    TM_FEBRUARY,
  304.     "March",    TM_MARCH,
  305.     "April",    TM_APRIL,
  306.     "May",        TM_MAY,
  307.     "June",        TM_JUNE,
  308.     "July",        TM_JULY,
  309.     "August",    TM_AUGUST,
  310.     "September",    TM_SEPTEMBER,
  311.     "October",    TM_OCTOBER,
  312.     "November",    TM_NOVEMBER,
  313.     "December",    TM_DECEMBER,
  314.     NULL,        0
  315. };
  316.  
  317. static struct lookup const    wday_names[] = {
  318.     "Sunday",    TM_SUNDAY,
  319.     "Monday",    TM_MONDAY,
  320.     "Tuesday",    TM_TUESDAY,
  321.     "Wednesday",    TM_WEDNESDAY,
  322.     "Thursday",    TM_THURSDAY,
  323.     "Friday",    TM_FRIDAY,
  324.     "Saturday",    TM_SATURDAY,
  325.     NULL,        0
  326. };
  327.  
  328. static struct lookup const    lasts[] = {
  329.     "last-Sunday",        TM_SUNDAY,
  330.     "last-Monday",        TM_MONDAY,
  331.     "last-Tuesday",        TM_TUESDAY,
  332.     "last-Wednesday",    TM_WEDNESDAY,
  333.     "last-Thursday",    TM_THURSDAY,
  334.     "last-Friday",        TM_FRIDAY,
  335.     "last-Saturday",    TM_SATURDAY,
  336.     NULL,            0
  337. };
  338.  
  339. static struct lookup const    begin_years[] = {
  340.     "minimum",        YR_MINIMUM,
  341.     "maximum",        YR_MAXIMUM,
  342.     NULL,            0
  343. };
  344.  
  345. static struct lookup const    end_years[] = {
  346.     "minimum",        YR_MINIMUM,
  347.     "maximum",        YR_MAXIMUM,
  348.     "only",            YR_ONLY,
  349.     NULL,            0
  350. };
  351.  
  352. static struct lookup const    leap_types[] = {
  353.     "Rolling",        TRUE,
  354.     "Stationary",        FALSE,
  355.     NULL,            0
  356. };
  357.  
  358. static const int    len_months[2][MONSPERYEAR] = {
  359.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  360.     31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  361. };
  362.  
  363. static const int    len_years[2] = {
  364.     DAYSPERNYEAR, DAYSPERLYEAR
  365. };
  366.  
  367. static time_t        ats[TZ_MAX_TIMES];
  368. static unsigned char    types[TZ_MAX_TIMES];
  369. static long        gmtoffs[TZ_MAX_TYPES];
  370. static char        isdsts[TZ_MAX_TYPES];
  371. static char        abbrinds[TZ_MAX_TYPES];
  372. static char        ttisstds[TZ_MAX_TYPES];
  373. static char        chars[TZ_MAX_CHARS];
  374. static time_t        trans[TZ_MAX_LEAPS];
  375. static long        corr[TZ_MAX_LEAPS];
  376. static char        roll[TZ_MAX_LEAPS];
  377.  
  378. /*
  379. ** Memory allocation.
  380. */
  381.  
  382. static char *
  383. memcheck(char *ptr)
  384. {
  385.     if (ptr == NULL) {
  386.         (void) perror(progname);
  387.         (void) exit(EXIT_FAILURE);
  388.     }
  389.     return ptr;
  390. }
  391.  
  392. #define emalloc(size)        memcheck(imalloc(size))
  393. #define erealloc(ptr, size)    memcheck(irealloc(ptr, size))
  394. #define ecpyalloc(ptr)        memcheck(icpyalloc(ptr))
  395. #define ecatalloc(oldp, newp)    memcheck(icatalloc(oldp, newp))
  396.  
  397. /*
  398. ** Error handling.
  399. */
  400.  
  401. static void
  402. eats(const char *name, int num, const char *rname, int rnum)
  403. {
  404.     filename = name;
  405.     linenum = num;
  406.     rfilename = rname;
  407.     rlinenum = rnum;
  408. }
  409.  
  410. static void
  411. eat(const char *name, int num)
  412. {
  413.     eats(name, num, (char *) NULL, -1);
  414. }
  415.  
  416. static void
  417. error(const char *string)
  418. {
  419.     /*
  420.     ** Match the format of "cc" to allow sh users to
  421.     **     zic ... 2>&1 | error -t "*" -v
  422.     ** on BSD systems.
  423.     */
  424.     (void) fprintf(stderr, "\"%s\", line %d: %s",
  425.         filename, linenum, string);
  426.     if (rfilename != NULL)
  427.         (void) fprintf(stderr, " (rule from \"%s\", line %d)",
  428.             rfilename, rlinenum);
  429.     (void) fprintf(stderr, "\n");
  430.     ++errors;
  431. }
  432.  
  433. static void
  434. usage(void)
  435. {
  436.     (void) fprintf(stderr,
  437. "%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ]\n\
  438. \t[ -L leapseconds ] [ filename ... ]\n",
  439.         progname, progname);
  440.     (void) exit(EXIT_FAILURE);
  441. }
  442.  
  443. static const char *    psxrules = NULL;
  444. static const char *    lcltime = NULL;
  445. static const char *    directory = NULL;
  446. static const char *    leapsec = NULL;
  447. static int        sflag = FALSE;
  448.  
  449. int
  450. main(int argc, char **argv)
  451. {
  452.     register int    i, j;
  453.     register int    c;
  454.  
  455.     (void) umask(umask(022) | 022);
  456.     progname = argv[0];
  457.     while ((c = getopt(argc, argv, "d:l:p:L:vs")) != EOF)
  458.         switch (c) {
  459.             default:
  460.                 usage();
  461.             case 'd':
  462.                 if (directory == NULL)
  463.                     directory = optarg;
  464.                 else {
  465.                     (void) fprintf(stderr,
  466. "%s: More than one -d option specified\n",
  467.                         progname);
  468.                     (void) exit(EXIT_FAILURE);
  469.                 }
  470.                 break;
  471.             case 'l':
  472.                 if (lcltime == NULL)
  473.                     lcltime = optarg;
  474.                 else {
  475.                     (void) fprintf(stderr,
  476. "%s: More than one -l option specified\n",
  477.                         progname);
  478.                     (void) exit(EXIT_FAILURE);
  479.                 }
  480.                 break;
  481.             case 'p':
  482.                 if (psxrules == NULL)
  483.                     psxrules = optarg;
  484.                 else {
  485.                     (void) fprintf(stderr,
  486. "%s: More than one -p option specified\n",
  487.                         progname);
  488.                     (void) exit(EXIT_FAILURE);
  489.                 }
  490.                 break;
  491.             case 'L':
  492.                 if (leapsec == NULL)
  493.                     leapsec = optarg;
  494.                 else {
  495.                     (void) fprintf(stderr,
  496. "%s: More than one -L option specified\n",
  497.                         progname);
  498.                     (void) exit(EXIT_FAILURE);
  499.                 }
  500.                 break;
  501.             case 'v':
  502.                 noise = TRUE;
  503.                 break;
  504.             case 's':
  505.                 sflag = TRUE;
  506.                 break;
  507.         }
  508.     if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
  509.         usage();    /* usage message by request */
  510.     if (directory == NULL)
  511.         directory = TZDIR;
  512.  
  513.     setboundaries();
  514.  
  515.     if (optind < argc && leapsec != NULL) {
  516.         infile(leapsec);
  517.         adjleap();
  518.     }
  519.  
  520.     zones = (struct zone *) emalloc(0);
  521.     rules = (struct rule *) emalloc(0);
  522.     links = (struct link *) emalloc(0);
  523.     for (i = optind; i < argc; ++i)
  524.         infile(argv[i]);
  525.     if (errors)
  526.         (void) exit(EXIT_FAILURE);
  527.     associate();
  528.     for (i = 0; i < nzones; i = j) {
  529.         /*
  530.         ** Find the next non-continuation zone entry.
  531.         */
  532.         for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
  533.             ;
  534.         outzone(&zones[i], j - i);
  535.     }
  536.     /*
  537.     ** Make links.
  538.     */
  539.     for (i = 0; i < nlinks; ++i)
  540.         dolink(links[i].l_from, links[i].l_to);
  541.     if (lcltime != NULL)
  542.         dolink(lcltime, TZDEFAULT);
  543.     if (psxrules != NULL)
  544.         dolink(psxrules, TZDEFRULES);
  545.     return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
  546. }
  547.  
  548. static void
  549. dolink(const char *fromfile, const char *tofile)
  550. {
  551.     register char *    fromname;
  552.     register char *    toname;
  553.  
  554.     fromname = ecpyalloc(directory);
  555.     fromname = ecatalloc(fromname, "/");
  556.     fromname = ecatalloc(fromname, fromfile);
  557.     if (strchr(tofile, ':')) toname = ecpyalloc(tofile);
  558.     else
  559.       {
  560.         toname = ecpyalloc(directory);
  561.         toname = ecatalloc(toname, "/");
  562.         toname = ecatalloc(toname, tofile);
  563.       }
  564.     /*
  565.     ** We get to be careful here since
  566.     ** there's a fair chance of root running us.
  567.     */
  568.     if (!itsdir(toname))
  569.         (void) remove(toname);
  570.     if (link(fromname, toname) != 0) {
  571.         (void) fprintf(stderr, "%s: Can't link from %s to ",
  572.             progname, fromname);
  573.         (void) perror(toname);
  574.         (void) exit(EXIT_FAILURE);
  575.     }
  576.     ifree(fromname);
  577.     ifree(toname);
  578. }
  579.  
  580. static void
  581. setboundaries(void)
  582. {
  583.     register time_t    bit;
  584.  
  585.     for (bit = 1; bit > 0; bit <<= 1)
  586.         ;
  587.     if (bit == 0) {        /* time_t is an unsigned type */
  588.         tt_signed = FALSE;
  589.         min_time = 0;
  590.         max_time = ~(time_t) 0;
  591.         if (sflag)
  592.             max_time >>= 1;
  593.     } else {
  594.         tt_signed = TRUE;
  595.         min_time = bit;
  596.         max_time = bit;
  597.         ++max_time;
  598.         max_time = -max_time;
  599.         if (sflag)
  600.             min_time = 0;
  601.     }
  602.     min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
  603.     max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
  604. }
  605.  
  606. static int
  607. itsdir(const char *name)
  608. {
  609.     struct stat    s;
  610.  
  611.     return (stat(name, &s) == 0 && S_ISDIR(s.st_mode));
  612. }
  613.  
  614. /*
  615. ** Associate sets of rules with zones.
  616. */
  617.  
  618. /*
  619. ** Sort by rule name.
  620. */
  621.  
  622. static int
  623. rcomp(const void * cp1, const void * cp2)
  624. {
  625.     return strcmp(((struct rule *) cp1)->r_name,
  626.         ((struct rule *) cp2)->r_name);
  627. }
  628.  
  629. static void
  630. associate(void)
  631. {
  632.     register struct zone *    zp;
  633.     register struct rule *    rp;
  634.     register int        base, out;
  635.     register int        i;
  636.  
  637.     if (nrules != 0)
  638.         (void) qsort((void *) rules, (size_t) nrules,
  639.              (size_t) sizeof *rules, rcomp);
  640.     for (i = 0; i < nzones; ++i) {
  641.         zp = &zones[i];
  642.         zp->z_rules = NULL;
  643.         zp->z_nrules = 0;
  644.     }
  645.     for (base = 0; base < nrules; base = out) {
  646.         rp = &rules[base];
  647.         for (out = base + 1; out < nrules; ++out)
  648.             if (strcmp(rp->r_name, rules[out].r_name) != 0)
  649.                 break;
  650.         for (i = 0; i < nzones; ++i) {
  651.             zp = &zones[i];
  652.             if (strcmp(zp->z_rule, rp->r_name) != 0)
  653.                 continue;
  654.             zp->z_rules = rp;
  655.             zp->z_nrules = out - base;
  656.         }
  657.     }
  658.     for (i = 0; i < nzones; ++i) {
  659.         zp = &zones[i];
  660.         if (zp->z_nrules == 0) {
  661.             /*
  662.             ** Maybe we have a local standard time offset.
  663.             */
  664.             eat(zp->z_filename, zp->z_linenum);
  665.             zp->z_stdoff =
  666.                 gethms((char *)zp->z_rule, "unruly zone", TRUE);
  667.             /*
  668.             ** Note, though, that if there's no rule,
  669.             ** a '%s' in the format is a bad thing.
  670.             */
  671.             if (strchr(zp->z_format, '%') != 0)
  672.                 error("%s in ruleless zone");
  673.         }
  674.     }
  675.     if (errors)
  676.         (void) exit(EXIT_FAILURE);
  677. }
  678.  
  679. static void
  680. infile(const char * name)
  681. {
  682.     register FILE *            fp;
  683.     register char **        fields;
  684.     register char *            cp;
  685.     register const struct lookup *    lp;
  686.     register int            nfields;
  687.     register int            wantcont;
  688.     register int            num;
  689.     char                buf[BUFSIZ];
  690.  
  691.     if (strcmp(name, "-") == 0) {
  692.         name = "standard input";
  693.         fp = stdin;
  694.     } else if ((fp = fopen(name, "r")) == NULL) {
  695.         (void) fprintf(stderr, "%s: Can't open ", progname);
  696.         (void) perror(name);
  697.         (void) exit(EXIT_FAILURE);
  698.     }
  699.     wantcont = FALSE;
  700.     for (num = 1; ; ++num) {
  701.         eat(name, num);
  702.         if (fgets(buf, (int) sizeof buf, fp) != buf)
  703.             break;
  704.         cp = strchr(buf, '\n');
  705.         if (cp == NULL) {
  706.             error("line too long");
  707.             (void) exit(EXIT_FAILURE);
  708.         }
  709.         *cp = '\0';
  710.         fields = getfields(buf);
  711.         nfields = 0;
  712.         while (fields[nfields] != NULL) {
  713.             if (ciequal(fields[nfields], "-"))
  714.                 fields[nfields] = "";
  715.             ++nfields;
  716.         }
  717.         if (nfields == 0) {
  718.             /* nothing to do */
  719.         } else if (wantcont) {
  720.             wantcont = inzcont(fields, nfields);
  721.         } else {
  722.             lp = byword(fields[0], line_codes);
  723.             if (lp == NULL)
  724.                 error("input line of unknown type");
  725.             else switch ((int) (lp->l_value)) {
  726.                 case LC_RULE:
  727.                     inrule(fields, nfields);
  728.                     wantcont = FALSE;
  729.                     break;
  730.                 case LC_ZONE:
  731.                     wantcont = inzone(fields, nfields);
  732.                     break;
  733.                 case LC_LINK:
  734.                     inlink(fields, nfields);
  735.                     wantcont = FALSE;
  736.                     break;
  737.                 case LC_LEAP:
  738.                     if (name != leapsec)
  739.                         (void) fprintf(stderr,
  740. "%s: Leap line in non leap seconds file %s\n",
  741.                             progname, name);
  742.                     else    inleap(fields, nfields);
  743.                     wantcont = FALSE;
  744.                     break;
  745.                 default:    /* "cannot happen" */
  746.                     (void) fprintf(stderr,
  747. "%s: panic: Invalid l_value %d\n",
  748.                         progname, lp->l_value);
  749.                     (void) exit(EXIT_FAILURE);
  750.             }
  751.         }
  752.         ifree((char *) fields);
  753.     }
  754.     if (ferror(fp)) {
  755.         (void) fprintf(stderr, "%s: Error reading ", progname);
  756.         (void) perror(filename);
  757.         (void) exit(EXIT_FAILURE);
  758.     }
  759.     if (fp != stdin && fclose(fp)) {
  760.         (void) fprintf(stderr, "%s: Error closing ", progname);
  761.         (void) perror(filename);
  762.         (void) exit(EXIT_FAILURE);
  763.     }
  764.     if (wantcont)
  765.         error("expected continuation line not found");
  766. }
  767.  
  768. /*
  769. ** Convert a string of one of the forms
  770. **    h    -h     hh:mm    -hh:mm    hh:mm:ss    -hh:mm:ss
  771. ** into a number of seconds.
  772. ** A null string maps to zero.
  773. ** Call error with errstring and return zero on errors.
  774. */
  775.  
  776. static long
  777. gethms(char *string, const char *errstring, int signable)
  778. {
  779.     int    hh, mm, ss, sign;
  780.  
  781.     if (string == NULL || *string == '\0')
  782.         return 0;
  783.     if (!signable)
  784.         sign = 1;
  785.     else if (*string == '-') {
  786.         sign = -1;
  787.         ++string;
  788.     } else    sign = 1;
  789.     if (sscanf(string, "%d:%d:%d", &hh, &mm, &ss) == 3) ;
  790.     else if (sscanf(string, "%d:%d", &hh, &mm) == 2) ss = 0;
  791.     else if (sscanf(string, "%d", &hh) == 1) mm = ss = 0;
  792.     else
  793.     {
  794.         error(errstring);
  795.         return 0;
  796.     }
  797.     if (hh < 0 || hh >= HOURSPERDAY ||
  798.         mm < 0 || mm >= MINSPERHOUR ||
  799.         ss < 0 || ss > SECSPERMIN) {
  800.             error(errstring);
  801.             return 0;
  802.     }
  803.     return eitol(sign) *
  804.         (eitol(hh * MINSPERHOUR + mm) *
  805.         eitol(SECSPERMIN) + eitol(ss));
  806. }
  807.  
  808. static void
  809. inrule(char **fields, int nfields)
  810. {
  811.     static struct rule    r;
  812.  
  813.     if (nfields != RULE_FIELDS) {
  814.         error("wrong number of fields on Rule line");
  815.         return;
  816.     }
  817.     if (*fields[RF_NAME] == '\0') {
  818.         error("nameless rule");
  819.         return;
  820.     }
  821.     r.r_filename = filename;
  822.     r.r_linenum = linenum;
  823.     r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE);
  824.     rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
  825.         fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
  826.     r.r_name = ecpyalloc(fields[RF_NAME]);
  827.     r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
  828.     rules = (struct rule *) erealloc((char *) rules,
  829.         (int) ((nrules + 1) * sizeof *rules));
  830.     rules[nrules++] = r;
  831. }
  832.  
  833. static int
  834. inzone(char **fields, int nfields)
  835. {
  836.     register int    i;
  837.     char        buf[132];
  838.  
  839.     if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
  840.         error("wrong number of fields on Zone line");
  841.         return FALSE;
  842.     }
  843.     if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
  844.         (void) sprintf(buf,
  845.             "\"Zone %s\" line and -l option are mutually exclusive",
  846.             TZDEFAULT);
  847.         error(buf);
  848.         return FALSE;
  849.     }
  850.     if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
  851.         (void) sprintf(buf,
  852.             "\"Zone %s\" line and -p option are mutually exclusive",
  853.             TZDEFRULES);
  854.         error(buf);
  855.         return FALSE;
  856.     }
  857.     for (i = 0; i < nzones; ++i)
  858.         if (zones[i].z_name != NULL &&
  859.             strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
  860.                 (void) sprintf(buf,
  861. "duplicate zone name %s (file \"%s\", line %d)",
  862.                     fields[ZF_NAME],
  863.                     zones[i].z_filename,
  864.                     zones[i].z_linenum);
  865.                 error(buf);
  866.                 return FALSE;
  867.         }
  868.     return inzsub(fields, nfields, FALSE);
  869. }
  870.  
  871. static int
  872. inzcont(char **fields, int nfields)
  873. {
  874.     if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
  875.         error("wrong number of fields on Zone continuation line");
  876.         return FALSE;
  877.     }
  878.     return inzsub(fields, nfields, TRUE);
  879. }
  880.  
  881. static int
  882. inzsub(char **fields, int nfields, int iscont)
  883. {
  884.     register char *        cp;
  885.     static struct zone    z;
  886.     register int        i_gmtoff, i_rule, i_format;
  887.     register int        i_untilyear, i_untilmonth;
  888.     register int        i_untilday, i_untiltime;
  889.     register int        hasuntil;
  890.  
  891.     if (iscont) {
  892.         i_gmtoff = ZFC_GMTOFF;
  893.         i_rule = ZFC_RULE;
  894.         i_format = ZFC_FORMAT;
  895.         i_untilyear = ZFC_TILYEAR;
  896.         i_untilmonth = ZFC_TILMONTH;
  897.         i_untilday = ZFC_TILDAY;
  898.         i_untiltime = ZFC_TILTIME;
  899.         z.z_name = NULL;
  900.     } else {
  901.         i_gmtoff = ZF_GMTOFF;
  902.         i_rule = ZF_RULE;
  903.         i_format = ZF_FORMAT;
  904.         i_untilyear = ZF_TILYEAR;
  905.         i_untilmonth = ZF_TILMONTH;
  906.         i_untilday = ZF_TILDAY;
  907.         i_untiltime = ZF_TILTIME;
  908.         z.z_name = ecpyalloc(fields[ZF_NAME]);
  909.     }
  910.     z.z_filename = filename;
  911.     z.z_linenum = linenum;
  912.     z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE);
  913.     if ((cp = strchr(fields[i_format], '%')) != 0) {
  914.         if (*++cp != 's' || strchr(cp, '%') != 0) {
  915.             error("invalid abbreviation format");
  916.             return FALSE;
  917.         }
  918.     }
  919.     z.z_rule = ecpyalloc(fields[i_rule]);
  920.     z.z_format = ecpyalloc(fields[i_format]);
  921.     hasuntil = nfields > i_untilyear;
  922.     if (hasuntil) {
  923.         z.z_untilrule.r_filename = filename;
  924.         z.z_untilrule.r_linenum = linenum;
  925.         rulesub(&z.z_untilrule,
  926.             fields[i_untilyear],
  927.             "only",
  928.             "",
  929.             (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan",
  930.             (nfields > i_untilday) ? fields[i_untilday] : "1",
  931.             (nfields > i_untiltime) ? fields[i_untiltime] : "0");
  932.         z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear);
  933.         if (iscont && nzones > 0 && z.z_untiltime < max_time &&
  934.             z.z_untiltime > min_time &&
  935.             zones[nzones - 1].z_untiltime >= z.z_untiltime) {
  936. error("Zone continuation line end time is not after end time of previous line");
  937.             return FALSE;
  938.         }
  939.     }
  940.     zones = (struct zone *) erealloc((char *) zones,
  941.         (int) ((nzones + 1) * sizeof *zones));
  942.     zones[nzones++] = z;
  943.     /*
  944.     ** If there was an UNTIL field on this line,
  945.     ** there's more information about the zone on the next line.
  946.     */
  947.     return hasuntil;
  948. }
  949.  
  950. static void
  951. inleap(char **fields, int nfields)
  952. {
  953.     register const char *        cp;
  954.     register const struct lookup *    lp;
  955.     register int            i, j;
  956.     int                year, month, day;
  957.     long                dayoff, tod;
  958.     time_t                t;
  959.  
  960.     if (nfields != LEAP_FIELDS) {
  961.         error("wrong number of fields on Leap line");
  962.         return;
  963.     }
  964.     dayoff = 0;
  965.     cp = fields[LP_YEAR];
  966.     if (sscanf((char *)cp, "%d", &year) != 1 ||
  967.         year < min_year || year > max_year) {
  968.             /*
  969.              * Leapin' Lizards!
  970.              */
  971.             error("invalid leaping year");
  972.             return;
  973.     }
  974.     j = EPOCH_YEAR;
  975.     while (j != year) {
  976.         if (year > j) {
  977.             i = len_years[isleap(j)];
  978.             ++j;
  979.         } else {
  980.             --j;
  981.             i = -len_years[isleap(j)];
  982.         }
  983.         dayoff = oadd(dayoff, eitol(i));
  984.     }
  985.     if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
  986.         error("invalid month name");
  987.         return;
  988.     }
  989.     month = lp->l_value;
  990.     j = TM_JANUARY;
  991.     while (j != month) {
  992.         i = len_months[isleap(year)][j];
  993.         dayoff = oadd(dayoff, eitol(i));
  994.         ++j;
  995.     }
  996.     cp = fields[LP_DAY];
  997.     if (sscanf((char *)cp, "%d", &day) != 1 ||
  998.         day <= 0 || day > len_months[isleap(year)][month]) {
  999.             error("invalid day of month");
  1000.             return;
  1001.     }
  1002.     dayoff = oadd(dayoff, eitol(day - 1));
  1003.     if (dayoff < 0 && !tt_signed) {
  1004.         error("time before zero");
  1005.         return;
  1006.     }
  1007.     t = (time_t) dayoff * SECSPERDAY;
  1008.     /*
  1009.     ** Cheap overflow check.
  1010.     */
  1011.     if (t / SECSPERDAY != dayoff) {
  1012.         error("time overflow");
  1013.         return;
  1014.     }
  1015.     tod = gethms(fields[LP_TIME], "invalid time of day", FALSE);
  1016.     cp = fields[LP_CORR];
  1017.     if (strcmp(cp, "+") != 0 && strcmp(cp, "") != 0) {
  1018.         /* infile() turned "-" into "" */
  1019.         error("illegal CORRECTION field on Leap line");
  1020.         return;
  1021.     }
  1022.     if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
  1023.         error("illegal Rolling/Stationary field on Leap line");
  1024.         return;
  1025.     }
  1026.     addleap(tadd(t, tod), *cp == '+', lp->l_value);
  1027. }
  1028.  
  1029. static void
  1030. inlink(char **fields, int nfields)
  1031. {
  1032.     struct link    l;
  1033.  
  1034.     if (nfields != LINK_FIELDS) {
  1035.         error("wrong number of fields on Link line");
  1036.         return;
  1037.     }
  1038.     if (*fields[LF_FROM] == '\0') {
  1039.         error("blank FROM field on Link line");
  1040.         return;
  1041.     }
  1042.     if (*fields[LF_TO] == '\0') {
  1043.         error("blank TO field on Link line");
  1044.         return;
  1045.     }
  1046.     l.l_filename = filename;
  1047.     l.l_linenum = linenum;
  1048.     l.l_from = ecpyalloc(fields[LF_FROM]);
  1049.     l.l_to = ecpyalloc(fields[LF_TO]);
  1050.     links = (struct link *) erealloc((char *) links,
  1051.         (int) ((nlinks + 1) * sizeof *links));
  1052.     links[nlinks++] = l;
  1053. }
  1054.  
  1055. static void
  1056. rulesub(struct rule *rp,
  1057.     char *loyearp,
  1058.     char *hiyearp,
  1059.     char *typep,
  1060.     char *monthp,
  1061.     char *dayp,
  1062.     char *timep)
  1063. {
  1064.     register struct lookup const *    lp;
  1065.     register char *            cp;
  1066.  
  1067.     if ((lp = byword(monthp, mon_names)) == NULL) {
  1068.         error("invalid month name");
  1069.         return;
  1070.     }
  1071.     rp->r_month = lp->l_value;
  1072.     rp->r_todisstd = FALSE;
  1073.     cp = timep;
  1074.     if (*cp != '\0') {
  1075.         cp += strlen(cp) - 1;
  1076.         switch (lowerit(*cp)) {
  1077.             case 's':
  1078.                 rp->r_todisstd = TRUE;
  1079.                 *cp = '\0';
  1080.                 break;
  1081.             case 'w':
  1082.                 rp->r_todisstd = FALSE;
  1083.                 *cp = '\0';
  1084.                 break;
  1085.         }
  1086.     }
  1087.     rp->r_tod = gethms(timep, "invalid time of day", FALSE);
  1088.     /*
  1089.     ** Year work.
  1090.     */
  1091.     cp = loyearp;
  1092.     if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) {
  1093.         case YR_MINIMUM:
  1094.             rp->r_loyear = min_year;
  1095.             break;
  1096.         case YR_MAXIMUM:
  1097.             rp->r_loyear = max_year;
  1098.             break;
  1099.         default:    /* "cannot happen" */
  1100.             (void) fprintf(stderr,
  1101.                 "%s: panic: Invalid l_value %d\n",
  1102.                 progname, lp->l_value);
  1103.             (void) exit(EXIT_FAILURE);
  1104.     } else if (sscanf(cp, "%d", &rp->r_loyear) != 1 ||
  1105.         rp->r_loyear < min_year || rp->r_loyear > max_year) {
  1106.             if (noise)
  1107.                 error("invalid starting year");
  1108.             if (rp->r_loyear > max_year)
  1109.                 return;
  1110.     }
  1111.     cp = hiyearp;
  1112.     if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
  1113.         case YR_MINIMUM:
  1114.             rp->r_hiyear = min_year;
  1115.             break;
  1116.         case YR_MAXIMUM:
  1117.             rp->r_hiyear = max_year;
  1118.             break;
  1119.         case YR_ONLY:
  1120.             rp->r_hiyear = rp->r_loyear;
  1121.             break;
  1122.         default:    /* "cannot happen" */
  1123.             (void) fprintf(stderr,
  1124.                 "%s: panic: Invalid l_value %d\n",
  1125.                 progname, lp->l_value);
  1126.             (void) exit(EXIT_FAILURE);
  1127.     } else if (sscanf(cp, "%d", &rp->r_hiyear) != 1 ||
  1128.         rp->r_hiyear < min_year || rp->r_hiyear > max_year) {
  1129.             if (noise)
  1130.                 error("invalid ending year");
  1131.             if (rp->r_hiyear < min_year)
  1132.                 return;
  1133.     }
  1134.     if (rp->r_hiyear < min_year)
  1135.          return;
  1136.      if (rp->r_loyear < min_year)
  1137.          rp->r_loyear = min_year;
  1138.      if (rp->r_hiyear > max_year)
  1139.          rp->r_hiyear = max_year;
  1140.     if (rp->r_loyear > rp->r_hiyear) {
  1141.         error("starting year greater than ending year");
  1142.         return;
  1143.     }
  1144.     if (*typep == '\0')
  1145.         rp->r_yrtype = NULL;
  1146.     else {
  1147.         if (rp->r_loyear == rp->r_hiyear) {
  1148.             error("typed single year");
  1149.             return;
  1150.         }
  1151.         rp->r_yrtype = ecpyalloc(typep);
  1152.     }
  1153.     /*
  1154.     ** Day work.
  1155.     ** Accept things such as:
  1156.     **    1
  1157.     **    last-Sunday
  1158.     **    Sun<=20
  1159.     **    Sun>=7
  1160.     */
  1161.     if ((lp = byword(dayp, lasts)) != NULL) {
  1162.         rp->r_dycode = DC_DOWLEQ;
  1163.         rp->r_wday = lp->l_value;
  1164.         rp->r_dayofmonth = len_months[1][rp->r_month];
  1165.     } else {
  1166.         if ((cp = strchr(dayp, '<')) != 0)
  1167.             rp->r_dycode = DC_DOWLEQ;
  1168.         else if ((cp = strchr(dayp, '>')) != 0)
  1169.             rp->r_dycode = DC_DOWGEQ;
  1170.         else {
  1171.             cp = dayp;
  1172.             rp->r_dycode = DC_DOM;
  1173.         }
  1174.         if (rp->r_dycode != DC_DOM) {
  1175.             *cp++ = 0;
  1176.             if (*cp++ != '=') {
  1177.                 error("invalid day of month");
  1178.                 return;
  1179.             }
  1180.             if ((lp = byword(dayp, wday_names)) == NULL) {
  1181.                 error("invalid weekday name");
  1182.                 return;
  1183.             }
  1184.             rp->r_wday = lp->l_value;
  1185.         }
  1186.         if (sscanf(cp, "%d", &rp->r_dayofmonth) != 1 ||
  1187.             rp->r_dayofmonth <= 0 ||
  1188.             (rp->r_dayofmonth > len_months[1][rp->r_month])) {
  1189.                 error("invalid day of month");
  1190.                 return;
  1191.         }
  1192.     }
  1193. }
  1194.  
  1195. static void
  1196. convert(long val, char *buf)
  1197. {
  1198.     register int    i;
  1199.     register long    shift;
  1200.  
  1201.     for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
  1202.         buf[i] = val >> shift;
  1203. }
  1204.  
  1205. static void
  1206. puttzcode(long val, FILE *fp)
  1207. {
  1208.     char    buf[4];
  1209.  
  1210.     convert(val, buf);
  1211.     (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
  1212. }
  1213.  
  1214. static void
  1215. writezone(const char *name)
  1216. {
  1217.     register FILE *        fp;
  1218.     register int        i, j;
  1219.     char            fullname[BUFSIZ];
  1220.     static struct tzhead    tzh;
  1221.  
  1222.     if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) {
  1223.         (void) fprintf(stderr,
  1224.             "%s: File name %s/%s too long\n", progname,
  1225.             directory, name);
  1226.         (void) exit(EXIT_FAILURE);
  1227.     }
  1228.     (void) sprintf(fullname, "%s/%s", directory, name);
  1229.     if ((fp = fopen(fullname, "wb")) == NULL) {
  1230.         if (mkdirs(fullname) != 0)
  1231.             (void) exit(EXIT_FAILURE);
  1232.         if ((fp = fopen(fullname, "wb")) == NULL) {
  1233.             (void) fprintf(stderr, "%s: Can't create ", progname);
  1234.             (void) perror(fullname);
  1235.             (void) exit(EXIT_FAILURE);
  1236.         }
  1237.     }
  1238.     convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
  1239.     convert(eitol(leapcnt), tzh.tzh_leapcnt);
  1240.     convert(eitol(timecnt), tzh.tzh_timecnt);
  1241.     convert(eitol(typecnt), tzh.tzh_typecnt);
  1242.     convert(eitol(charcnt), tzh.tzh_charcnt);
  1243.     (void) fwrite((void *) &tzh, (size_t) sizeof tzh, (size_t) 1, fp);
  1244.     for (i = 0; i < timecnt; ++i) {
  1245.         j = leapcnt;
  1246.         while (--j >= 0)
  1247.             if (ats[i] >= trans[j]) {
  1248.                 ats[i] = tadd(ats[i], corr[j]);
  1249.                 break;
  1250.             }
  1251.         puttzcode((long) ats[i], fp);
  1252.     }
  1253.     if (timecnt > 0)
  1254.         (void) fwrite((void *) types, (size_t) sizeof types[0],
  1255.             (size_t) timecnt, fp);
  1256.     for (i = 0; i < typecnt; ++i) {
  1257.         puttzcode((long) gmtoffs[i], fp);
  1258.         (void) putc(isdsts[i], fp);
  1259.         (void) putc(abbrinds[i], fp);
  1260.     }
  1261.     if (charcnt != 0)
  1262.         (void) fwrite((void *) chars, (size_t) sizeof chars[0],
  1263.             (size_t) charcnt, fp);
  1264.     for (i = 0; i < leapcnt; ++i) {
  1265.         if (roll[i]) {
  1266.             if (timecnt == 0 || trans[i] < ats[0]) {
  1267.                 j = 0;
  1268.                 while (isdsts[j])
  1269.                     if (++j >= typecnt) {
  1270.                         j = 0;
  1271.                         break;
  1272.                     }
  1273.             } else {
  1274.                 j = 1;
  1275.                 while (j < timecnt && trans[i] >= ats[j])
  1276.                     ++j;
  1277.                 j = types[j - 1];
  1278.             }
  1279.             puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
  1280.         } else    puttzcode((long) trans[i], fp);
  1281.         puttzcode((long) corr[i], fp);
  1282.     }
  1283.     for (i = 0; i < typecnt; ++i)
  1284.         (void) putc(ttisstds[i], fp);
  1285.     if (ferror(fp) || fclose(fp)) {
  1286.         (void) fprintf(stderr, "%s: Write error on ", progname);
  1287.         (void) perror(fullname);
  1288.         (void) exit(EXIT_FAILURE);
  1289.     }
  1290. }
  1291.  
  1292. static void
  1293. outzone(const struct zone *zpfirst, int zonecount)
  1294. {
  1295.     register const struct zone *    zp;
  1296.     register struct rule *        rp;
  1297.     register int            i, j;
  1298.     register int            usestart, useuntil;
  1299.     register time_t            starttime, untiltime;
  1300.     register long            gmtoff;
  1301.     register long            stdoff;
  1302.     register int            year;
  1303.     register long            startoff;
  1304.     register int            startisdst;
  1305.     register int            startttisstd;
  1306.     register int            type;
  1307.     char                startbuf[BUFSIZ];
  1308.  
  1309.     /*
  1310.     ** Now. . .finally. . .generate some useful data!
  1311.     */
  1312.     timecnt = 0;
  1313.     typecnt = 0;
  1314.     charcnt = 0;
  1315.     /*
  1316.     ** Two guesses. . .the second may well be corrected later.
  1317.     */
  1318.     gmtoff = zpfirst->z_gmtoff;
  1319.     stdoff = 0;
  1320. #ifdef lint
  1321.     starttime = 0;
  1322.     startttisstd = FALSE;
  1323. #endif /* defined lint */
  1324.     for (i = 0; i < zonecount; ++i) {
  1325.         usestart = i > 0;
  1326.         useuntil = i < (zonecount - 1);
  1327.         zp = &zpfirst[i];
  1328.         eat(zp->z_filename, zp->z_linenum);
  1329.         startisdst = -1;
  1330.         if (zp->z_nrules == 0) {
  1331.             type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff),
  1332.                 zp->z_format, zp->z_stdoff != 0,
  1333.                 startttisstd);
  1334.             if (usestart)
  1335.                 addtt(starttime, type);
  1336.             gmtoff = zp->z_gmtoff;
  1337.             stdoff = zp->z_stdoff;
  1338.         } else for (year = min_year; year <= max_year; ++year) {
  1339.             if (useuntil && year > zp->z_untilrule.r_hiyear)
  1340.                 break;
  1341.             /*
  1342.             ** Mark which rules to do in the current year.
  1343.             ** For those to do, calculate rpytime(rp, year);
  1344.             */
  1345.             for (j = 0; j < zp->z_nrules; ++j) {
  1346.                 rp = &zp->z_rules[j];
  1347.                 eats(zp->z_filename, zp->z_linenum,
  1348.                     rp->r_filename, rp->r_linenum);
  1349.                 rp->r_todo = year >= rp->r_loyear &&
  1350.                         year <= rp->r_hiyear &&
  1351.                         yearistype(year, rp->r_yrtype);
  1352.                 if (rp->r_todo)
  1353.                     rp->r_temp = rpytime(rp, year);
  1354.             }
  1355.             for ( ; ; ) {
  1356.                 register int    k;
  1357.                 register time_t    jtime, ktime;
  1358.                 register long    offset;
  1359.                 char        buf[BUFSIZ];
  1360.  
  1361.                 if (useuntil) {
  1362.                     /*
  1363.                     ** Turn untiltime into GMT
  1364.                     ** assuming the current gmtoff and
  1365.                     ** stdoff values.
  1366.                     */
  1367.                     offset = gmtoff;
  1368.                     if (!zp->z_untilrule.r_todisstd)
  1369.                         offset = oadd(offset, stdoff);
  1370.                     untiltime = tadd(zp->z_untiltime,
  1371.                         -offset);
  1372.                 }
  1373.                 /*
  1374.                 ** Find the rule (of those to do, if any)
  1375.                 ** that takes effect earliest in the year.
  1376.                 */
  1377.                 k = -1;
  1378. #ifdef lint
  1379.                 ktime = 0;
  1380. #endif /* defined lint */
  1381.                 for (j = 0; j < zp->z_nrules; ++j) {
  1382.                     rp = &zp->z_rules[j];
  1383.                     if (!rp->r_todo)
  1384.                         continue;
  1385.                     eats(zp->z_filename, zp->z_linenum,
  1386.                         rp->r_filename, rp->r_linenum);
  1387.                     offset = gmtoff;
  1388.                     if (!rp->r_todisstd)
  1389.                         offset = oadd(offset, stdoff);
  1390.                     jtime = rp->r_temp;
  1391.                     if (jtime == min_time ||
  1392.                         jtime == max_time)
  1393.                             continue;
  1394.                     jtime = tadd(jtime, -offset);
  1395.                     if (k < 0 || jtime < ktime) {
  1396.                         k = j;
  1397.                         ktime = jtime;
  1398.                     }
  1399.                 }
  1400.                 if (k < 0)
  1401.                     break;    /* go on to next year */
  1402.                 rp = &zp->z_rules[k];
  1403.                 rp->r_todo = FALSE;
  1404.                 if (useuntil && ktime >= untiltime)
  1405.                     break;
  1406.                 if (usestart) {
  1407.                     if (ktime < starttime) {
  1408.                         stdoff = rp->r_stdoff;
  1409.                         startoff = oadd(zp->z_gmtoff,
  1410.                             rp->r_stdoff);
  1411.                         (void) sprintf(startbuf,
  1412.                             zp->z_format,
  1413.                             rp->r_abbrvar);
  1414.                         startisdst =
  1415.                             rp->r_stdoff != 0;
  1416.                         continue;
  1417.                     }
  1418.                     if (ktime != starttime &&
  1419.                         startisdst >= 0)
  1420. addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd));
  1421.                     usestart = FALSE;
  1422.                 }
  1423.                 eats(zp->z_filename, zp->z_linenum,
  1424.                     rp->r_filename, rp->r_linenum);
  1425.                 (void) sprintf(buf, zp->z_format,
  1426.                     rp->r_abbrvar);
  1427.                 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
  1428.                 type = addtype(offset, buf, rp->r_stdoff != 0,
  1429.                     rp->r_todisstd);
  1430.                 if (timecnt != 0 || rp->r_stdoff != 0)
  1431.                     addtt(ktime, type);
  1432.                 gmtoff = zp->z_gmtoff;
  1433.                 stdoff = rp->r_stdoff;
  1434.             }
  1435.         }
  1436.         /*
  1437.         ** Now we may get to set starttime for the next zone line.
  1438.         */
  1439.         if (useuntil) {
  1440.             starttime = tadd(zp->z_untiltime,
  1441.                 -gmtoffs[types[timecnt - 1]]);
  1442.             startttisstd = zp->z_untilrule.r_todisstd;
  1443.         }
  1444.     }
  1445.     writezone(zpfirst->z_name);
  1446. }
  1447.  
  1448. static void
  1449. addtt(time_t starttime, int type)
  1450. {
  1451.     if (timecnt != 0 && type == types[timecnt - 1])
  1452.         return;    /* easy enough! */
  1453.     if (timecnt >= TZ_MAX_TIMES) {
  1454.         error("too many transitions?!");
  1455.         (void) exit(EXIT_FAILURE);
  1456.     }
  1457.     ats[timecnt] = starttime;
  1458.     types[timecnt] = type;
  1459.     ++timecnt;
  1460. }
  1461.  
  1462. static int
  1463. addtype(long gmtoff, const char *abbr, int isdst, int ttisstd)
  1464. {
  1465.     register int    i, j;
  1466.  
  1467.     /*
  1468.     ** See if there's already an entry for this zone type.
  1469.     ** If so, just return its index.
  1470.     */
  1471.     for (i = 0; i < typecnt; ++i) {
  1472.         if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
  1473.             strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
  1474.             ttisstd == ttisstds[i])
  1475.                 return i;
  1476.     }
  1477.     /*
  1478.     ** There isn't one; add a new one, unless there are already too
  1479.     ** many.
  1480.     */
  1481.     if (typecnt >= TZ_MAX_TYPES) {
  1482.         error("too many local time types");
  1483.         (void) exit(EXIT_FAILURE);
  1484.     }
  1485.     gmtoffs[i] = gmtoff;
  1486.     isdsts[i] = isdst;
  1487.     ttisstds[i] = ttisstd;
  1488.  
  1489.     for (j = 0; j < charcnt; ++j)
  1490.         if (strcmp(&chars[j], abbr) == 0)
  1491.             break;
  1492.     if (j == charcnt)
  1493.         newabbr(abbr);
  1494.     abbrinds[i] = j;
  1495.     ++typecnt;
  1496.     return i;
  1497. }
  1498.  
  1499. static void
  1500. addleap(time_t t, int positive, int rolling)
  1501. {
  1502.     register int    i, j;
  1503.  
  1504.     if (leapcnt >= TZ_MAX_LEAPS) {
  1505.         error("too many leap seconds");
  1506.         (void) exit(EXIT_FAILURE);
  1507.     }
  1508.     for (i = 0; i < leapcnt; ++i)
  1509.         if (t <= trans[i]) {
  1510.             if (t == trans[i]) {
  1511.                 error("repeated leap second moment");
  1512.                 (void) exit(EXIT_FAILURE);
  1513.             }
  1514.             break;
  1515.         }
  1516.     for (j = leapcnt; j > i; --j) {
  1517.         trans[j] = trans[j-1];
  1518.         corr[j] = corr[j-1];
  1519.         roll[j] = roll[j-1];
  1520.     }
  1521.     trans[i] = t;
  1522.     corr[i] = (positive ? 1L : -1L);
  1523.     roll[i] = rolling;
  1524.     ++leapcnt;
  1525. }
  1526.  
  1527. static void
  1528. adjleap(void)
  1529. {
  1530.     register int    i;
  1531.     register long    last = 0;
  1532.  
  1533.     /*
  1534.     ** propagate leap seconds forward
  1535.     */
  1536.     for (i = 0; i < leapcnt; ++i) {
  1537.         trans[i] = tadd(trans[i], last);
  1538.         last = corr[i] += last;
  1539.     }
  1540. }
  1541.  
  1542. static int
  1543. yearistype(int year, const char *type)
  1544. {
  1545.     char    buf[BUFSIZ];
  1546.     int    result;
  1547.  
  1548.     if (type == NULL || *type == '\0')
  1549.         return TRUE;
  1550.     if (strcmp(type, "uspres") == 0)
  1551.         return (year % 4) == 0;
  1552.     if (strcmp(type, "nonpres") == 0)
  1553.         return (year % 4) != 0;
  1554.     (void) sprintf(buf, "yearistype %d %s", year, type);
  1555.     result = system(buf);
  1556.     if (result == 0)
  1557.         return TRUE;
  1558.     if (result == (1 << 8))
  1559.         return FALSE;
  1560.     error("Wild result from command execution");
  1561.     (void) fprintf(stderr, "%s: command was '%s', result was %d\n",
  1562.         progname, buf, result);
  1563.     for ( ; ; )
  1564.         (void) exit(EXIT_FAILURE);
  1565. }
  1566.  
  1567. static int
  1568. lowerit(int a)
  1569. {
  1570.     return (isascii(a) && isupper(a)) ? tolower(a) : a;
  1571. }
  1572.  
  1573. /* case-insensitive equality */
  1574. static int
  1575. ciequal(register const char *ap, register const char *bp)
  1576. {
  1577.     while (lowerit(*ap) == lowerit(*bp++))
  1578.         if (*ap++ == '\0')
  1579.             return TRUE;
  1580.     return FALSE;
  1581. }
  1582.  
  1583. static int
  1584. itsabbr(register const char *abbr, register const char *word)
  1585. {
  1586.     if (lowerit(*abbr) != lowerit(*word))
  1587.         return FALSE;
  1588.     ++word;
  1589.     while (*++abbr != '\0')
  1590.         do if (*word == '\0')
  1591.             return FALSE;
  1592.                 while (lowerit(*word++) != lowerit(*abbr));
  1593.     return TRUE;
  1594. }
  1595.  
  1596. static const struct lookup *
  1597. byword( const char *word, const struct lookup *table)
  1598. {
  1599.     register const struct lookup *    foundlp;
  1600.     register const struct lookup *    lp;
  1601.  
  1602.     if (word == NULL || table == NULL)
  1603.         return NULL;
  1604.     /*
  1605.     ** Look for exact match.
  1606.     */
  1607.     for (lp = table; lp->l_word != NULL; ++lp)
  1608.         if (ciequal(word, lp->l_word))
  1609.             return lp;
  1610.     /*
  1611.     ** Look for inexact match.
  1612.     */
  1613.     foundlp = NULL;
  1614.     for (lp = table; lp->l_word != NULL; ++lp)
  1615.         if (itsabbr(word, lp->l_word))
  1616.             if (foundlp == NULL)
  1617.                 foundlp = lp;
  1618.             else    return NULL;    /* multiple inexact matches */
  1619.     return foundlp;
  1620. }
  1621.  
  1622. static char **
  1623. getfields(register char *cp)
  1624. {
  1625.     register char *        dp;
  1626.     register char **    array;
  1627.     register int        nsubs;
  1628.  
  1629.     if (cp == NULL)
  1630.         return NULL;
  1631.     array = (char **) emalloc((int) ((strlen(cp) + 1) * sizeof *array));
  1632.     nsubs = 0;
  1633.     for ( ; ; ) {
  1634.         while (isascii(*cp) && isspace(*cp))
  1635.             ++cp;
  1636.         if (*cp == '\0' || *cp == '#')
  1637.             break;
  1638.         array[nsubs++] = dp = cp;
  1639.         do {
  1640.             if ((*dp = *cp++) != '"')
  1641.                 ++dp;
  1642.             else while ((*dp = *cp++) != '"')
  1643.                 if (*dp != '\0')
  1644.                     ++dp;
  1645.                 else    error("Odd number of quotation marks");
  1646.         } while (*cp != '\0' && *cp != '#' &&
  1647.             (!isascii(*cp) || !isspace(*cp)));
  1648.         if (isascii(*cp) && isspace(*cp))
  1649.             ++cp;
  1650.         *dp = '\0';
  1651.     }
  1652.     array[nsubs] = NULL;
  1653.     return array;
  1654. }
  1655.  
  1656. static long
  1657. oadd(long t1, long t2)
  1658. {
  1659.     register long    t;
  1660.  
  1661.     t = t1 + t2;
  1662.     if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
  1663.         error("time overflow");
  1664.         (void) exit(EXIT_FAILURE);
  1665.     }
  1666.     return t;
  1667. }
  1668.  
  1669. static time_t
  1670. tadd(time_t t1, long t2)
  1671. {
  1672.     register time_t    t;
  1673.  
  1674.     if (t1 == max_time && t2 > 0)
  1675.         return max_time;
  1676.     if (t1 == min_time && t2 < 0)
  1677.         return min_time;
  1678.     t = t1 + t2;
  1679.     if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
  1680.         error("time overflow");
  1681.         (void) exit(EXIT_FAILURE);
  1682.     }
  1683.     return t;
  1684. }
  1685.  
  1686. /*
  1687. ** Given a rule, and a year, compute the date - in seconds since January 1,
  1688. ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
  1689. */
  1690.  
  1691. static time_t
  1692. rpytime(const struct rule *rp, int wantedy)
  1693. {
  1694.     register int    y, m, i;
  1695.     register long    dayoff;            /* with a nod to Margaret O. */
  1696.     register time_t    t;
  1697.  
  1698.     dayoff = 0;
  1699.     m = TM_JANUARY;
  1700.     y = EPOCH_YEAR;
  1701.     while (wantedy != y) {
  1702.         if (wantedy > y) {
  1703.             i = len_years[isleap(y)];
  1704.             ++y;
  1705.         } else {
  1706.             --y;
  1707.             i = -len_years[isleap(y)];
  1708.         }
  1709.         dayoff = oadd(dayoff, eitol(i));
  1710.     }
  1711.     while (m != rp->r_month) {
  1712.         i = len_months[isleap(y)][m];
  1713.         dayoff = oadd(dayoff, eitol(i));
  1714.         ++m;
  1715.     }
  1716.     i = rp->r_dayofmonth;
  1717.     if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
  1718.         if (rp->r_dycode == DC_DOWLEQ)
  1719.             --i;
  1720.         else {
  1721.             error("use of 2/29 in non leap-year");
  1722.             (void) exit(EXIT_FAILURE);
  1723.         }
  1724.     }
  1725.     --i;
  1726.     dayoff = oadd(dayoff, eitol(i));
  1727.     if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
  1728.         register long    wday;
  1729.  
  1730. #define LDAYSPERWEEK    ((long) DAYSPERWEEK)
  1731.         wday = eitol(EPOCH_WDAY);
  1732.         /*
  1733.         ** Don't trust mod of negative numbers.
  1734.         */
  1735.         if (dayoff >= 0)
  1736.             wday = (wday + dayoff) % LDAYSPERWEEK;
  1737.         else {
  1738.             wday -= ((-dayoff) % LDAYSPERWEEK);
  1739.             if (wday < 0)
  1740.                 wday += LDAYSPERWEEK;
  1741.         }
  1742.         while (wday != eitol(rp->r_wday))
  1743.             if (rp->r_dycode == DC_DOWGEQ) {
  1744.                 dayoff = oadd(dayoff, (long) 1);
  1745.                 if (++wday >= LDAYSPERWEEK)
  1746.                     wday = 0;
  1747.                 ++i;
  1748.             } else {
  1749.                 dayoff = oadd(dayoff, (long) -1);
  1750.                 if (--wday < 0)
  1751.                     wday = LDAYSPERWEEK;
  1752.                 --i;
  1753.             }
  1754.         if (i < 0 || i >= len_months[isleap(y)][m]) {
  1755.             error("no day in month matches rule");
  1756.             (void) exit(EXIT_FAILURE);
  1757.         }
  1758.     }
  1759.     if (dayoff < 0 && !tt_signed) {
  1760.         if (wantedy == rp->r_loyear)
  1761.             return min_time;
  1762.         error("time before zero");
  1763.         (void) exit(EXIT_FAILURE);
  1764.     }
  1765.     t = (time_t) dayoff * SECSPERDAY;
  1766.     /*
  1767.     ** Cheap overflow check.
  1768.     */
  1769.     if (t / SECSPERDAY != dayoff) {
  1770.         if (wantedy == rp->r_hiyear)
  1771.             return max_time;
  1772.         if (wantedy == rp->r_loyear)
  1773.             return min_time;
  1774.         error("time overflow");
  1775.         (void) exit(EXIT_FAILURE);
  1776.     }
  1777.     return tadd(t, rp->r_tod);
  1778. }
  1779.  
  1780. static void
  1781. newabbr(const char *string)
  1782. {
  1783.     register int    i;
  1784.  
  1785.     i = strlen(string) + 1;
  1786.     if (charcnt + i >= TZ_MAX_CHARS) {
  1787.         error("too many, or too long, time zone abbreviations");
  1788.         (void) exit(EXIT_FAILURE);
  1789.     }
  1790.     (void) strcpy(&chars[charcnt], string);
  1791.     charcnt += eitol(i);
  1792. }
  1793.  
  1794. static int
  1795. mkdirs(char *name)
  1796. {
  1797.     register char *    cp;
  1798.  
  1799.     if ((cp = name) == NULL || *cp == '\0')
  1800.         return 0;
  1801.     while ((cp = strchr(cp + 1, '/')) != 0) {
  1802.         *cp = '\0';
  1803.         if (!itsdir(name)) {
  1804.             /*
  1805.             ** It doesn't seem to exist, so we try to create it.
  1806.             */
  1807.             if (mkdir(name, 0755) != 0) {
  1808.                 (void) fprintf(stderr,
  1809.                     "%s: Can't create directory ",
  1810.                     progname);
  1811.                 (void) perror(name);
  1812.                 return -1;
  1813.             }
  1814.         }
  1815.         *cp = '/';
  1816.     }
  1817.     return 0;
  1818. }
  1819.  
  1820. static long
  1821. eitol(int i)
  1822. {
  1823.     long    l;
  1824.  
  1825.     l = i;
  1826.     if (i < 0 && l >= 0 || i == 0 && l != 0 || i > 0 && l <= 0) {
  1827.         (void) fprintf(stderr, "%s: %d did not sign extend correctly\n",
  1828.             progname, i);
  1829.         (void) exit(EXIT_FAILURE);
  1830.     }
  1831.     return l;
  1832. }
  1833.  
  1834. /*
  1835. ** UNIX is a registered trademark of AT&T.
  1836. */
  1837.